<template>
  <div class="container_box">
    <el-descriptions title="自定义tree组件">
      <el-descriptions-item label="描述">
        自己封装的自定义tree组件，根据el-tree懒加载模式进行封装，实现了某一层级节点多选的特定场景。
      </el-descriptions-item>
    </el-descriptions>
    <div class="flex gap-4 mb-4" style="margin: 12px 0">
      <span>示例为一二级节点单选，同一一级节点下的所有三级节点多选</span>
    </div>
    <div class="flex gap-4 mb-4" style="margin: 12px 0">
      <span>示例同时添加了下拉滚动加载</span>
    </div>
    <div
      class="infinite_list"
      :infinite-scroll-immediate="false"
      :infinite-scroll-delay="200"
      v-infinite-scroll="loadMore"
      :infinite-scroll-disabled="noMore"
      :infinite-scroll-distance="50"
    >
      <el-tree
        ref="treeRef"
        :props="treeProps"
        :load="loadNode"
        :highlight-current="true"
        lazy
        node-key="companyId"
        v-if="treeRefresh"
      >
        <template #default="{ node, data, store, self }">
          <el-checkbox
            v-model="node.checked"
            @change="handleCheckboxChange(node, data, store, self)"
            v-if="node.level === 3"
          ></el-checkbox>
          <span
            :title="data.personName || data.departmentName || data.companyName"
          >
            {{ data.personName || data.departmentName || data.companyName }}
          </span>
        </template>
      </el-tree>
      <p v-if="noMore" style="text-align: center">
        数据已到底，共{{ total }}条数据
      </p>
      <p v-else style="text-align: center">加载中...</p>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, toRefs, computed, shallowRef, nextTick } from "vue";

const treeRef = ref(null);

const templateResolveLevel = shallowRef(null); // 用于存储loadNode一级节点的resolve
const firstOnce = ref(true); // 控制一级节点请求接口
const state = reactive({
  treeRefresh: true,
  pageNum: 1,
  pageSize: 50,
  total: 0,
});
const { treeRefresh, total } = toRefs(state);

// el-tree props
const treeProps = {
  id: "companyId",
  label: "companyName",
  children: "zones",
  isLeaf: "leaf",
};

// 控制下拉加载和下拉加载文本
const noMore = computed(
  () =>
    state.pageNum > state.total / state.pageSize ||
    state.total <= state.pageSize,
);

// 下拉加载更多
const loadMore = () => {
  state.pageNum++;
  getFirstNodeDataList(templateResolveLevel.value);
};

// 加载渲染el-tree
const loadNode = (node, resolve) => {
  if (node.level === 0) {
    templateResolveLevel.value = resolve;
    if (firstOnce.value) {
      getFirstNodeDataList(resolve);
    }
  }
  if (node.level === 1) {
    getSecondlyNodeDataList(resolve);
  }
  if (node.level === 2) {
    getLastNodeDataList(resolve);
  }
};

// 获取一级节点列表
const getFirstNodeDataList = (resolve) => {
  if (!state.treeRefresh) {
    state.treeRefresh = true;
    return;
  }
  const data = generateCompanyData(state.pageNum, 50, "一级节点-企业");
  firstOnce.value = false;
  state.total = 101;
  nextTick(() => {
    return resolve(data);
  });
};

// 获取二级节点列表
const getSecondlyNodeDataList = (resolve) => {
  const data = generateCompanyDataSecondly(state.pageNum, 2, "二级节点-部门");
  setTimeout(() => {
    return resolve(data);
  }, 20);
};

// 获取三级节点列表
const getLastNodeDataList = (resolve) => {
  const data = generateCompanyDataThirdly(state.pageNum, 5, "三级节点-个人");
  setTimeout(() => {
    return resolve(data);
  }, 20);
};

// 选择复选框
const handleCheckboxChange = async (node, data, treeStore, self) => {
  if (node.level !== 3) return;
  // 清除其他节点下三级节点选择状态
  node.parent.parent.parent.childNodes.forEach((parent) => {
    if (parent !== node.parent.parent) {
      parent.childNodes.forEach((son) => {
        son.childNodes.forEach((grandson) => {
          grandson.checked = false;
        });
      });
    }
  });
  console.log(node, data, treeStore, self);
};

// 生成数据函数
const generateCompanyData = (pageNum, nums, prefix) => {
  const data = [];
  for (let i = 0; i < nums; i++) {
    const id = `${pageNum}${i + 1}`;
    const name = `${prefix}${id}`;
    data.push({
      companyId: id,
      companyName: name,
      leaf: false,
    });
  }
  return data;
};

const generateCompanyDataSecondly = (pageNum, nums, prefix) => {
  const data = [];
  for (let i = 0; i < nums; i++) {
    const id = `${pageNum}${i + 1}`;
    const name = `${prefix}${id}`;
    data.push({
      departmentId: id,
      departmentName: name,
      leaf: false,
    });
  }
  return data;
};

const generateCompanyDataThirdly = (pageNum, nums, prefix) => {
  const data = [];
  for (let i = 0; i < nums; i++) {
    const id = `${pageNum}${i + 1}`;
    const name = `${prefix}${id}`;
    data.push({
      personId: id,
      personName: name,
      leaf: true,
    });
  }
  return data;
};
</script>

<style lang="less" scoped>
.infinite_list {
  height: 100%;
  overflow: hidden auto;
  p {
    font-size: 14px;
  }
}
:deep(.is-leaf) {
  display: none;
}
:deep(.el-tree-node__content) {
  width: 100%;
  box-sizing: border-box;
  > span {
    width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowarp;
  }
}
</style>
